package cn.sciento.boot.tenant.initializer;

import java.util.Map;
import java.util.Objects;

import cn.sciento.boot.tenant.annotation.TenantInit;
import cn.sciento.boot.tenant.autoconfigure.TenantInitProperties;
import cn.sciento.boot.tenant.dto.TenantInitConfigDTO;
import cn.sciento.boot.tenant.feign.HiamFeignService;
import cn.sciento.boot.tenant.processor.TenantInitProcessor;
import cn.sciento.core.redis.RedisHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

/**
 * 注册租客初始化处理器
 */
@Component
public class TenantInitProcessorInitializer implements ApplicationListener<ContextRefreshedEvent> {
    private static final Logger LOGGER = LoggerFactory.getLogger(TenantInitProcessorInitializer.class);

    @Autowired
    private Environment environment;

    @Autowired
    private RedisHelper redisHelper;

    @Autowired
    private HiamFeignService hiamFeignService;

    @Autowired
    private TenantInitProperties tenantInitProperties;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        if (this.tenantInitProperties == null || !this.tenantInitProperties.getRegister().isEnabled()) {
            return;
        }
        ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
        Map<String, TenantInitProcessor> tenantInitProcessorMap = applicationContext.getBeansOfType(TenantInitProcessor.class);
        if (CollectionUtils.isEmpty(tenantInitProcessorMap)) {
            return;
        }
        tenantInitProcessorMap.forEach((beanName, beanInstance) -> {
            if (!AnnotationUtils.isAnnotationDeclaredLocally(TenantInit.class, beanInstance.getClass())) {
                LOGGER.warn("tenant init processor {} without annotation {}, cannot register.", beanName, TenantInit.class.getName());
                return;
            }
            TenantInit tenantInit = AnnotationUtils.getAnnotation(beanInstance.getClass(), TenantInit.class);
            TenantInitConfigDTO tenantInitConfigDTO = new TenantInitConfigDTO(this.environment.getProperty("spring.application.name"),
                    beanName, Objects.requireNonNull(tenantInit).processorName(), tenantInit.processorType(), tenantInit.initType(), tenantInit.orderSeq(), null);
            LOGGER.info("current register tenant init processor is {}.", tenantInitConfigDTO);
            TenantInitConfigDTO tenantInitConfigDTOCache = tenantInitConfigDTO.doFetchCache(this.redisHelper);
            if (tenantInitConfigDTOCache == null || !tenantInitConfigDTOCache.equals(tenantInitConfigDTO)) {
                this.hiamFeignService.registerTenantInitProcessor(tenantInitConfigDTO);
            } else {
                LOGGER.info("current register tenant init processor {} has been registered.", tenantInitConfigDTO);
            }
        });
    }
}
